<?php
/**
 * ANTFW functions package
 *
 * @author $AUTHOR$
 * @since $DATE$
 * @version $ID$
 */
defined('ANTFW_ROOT') || die('Access denied');


/**
 * Get/Set configure
 *
 * @param $key
 * @param $value
 * @param $merge
 * @return mixed
 */
function config($key, $value = DO_GET) {
    static $config = array();
    
    if (DO_MERGE === $value && is_array($key))
        $config = array_merge($config, $key);

    if (!is_string($key))
        return FALSE;

    $key = trim($key);
    if (!$key)
        return FALSE;

    if (DO_GET === $value)
        return isset($config[$key])? $config[$key]: NULL;

    $config[$key] = $value;
}

/**
 * Call class method
 *
 * @param string $classMethod
 * @param array $args
 * @param array $constructArgs
 * @return void
 *
 * @usage
 *  call(
 *      'c.index.index',
 *      $args = array(),
 *      $constructArgs = array()
 *  );
 */
function call($classMethod, $args = array(), $constructArgs = array()) {

    if (!($classMethod = trim($classMethod)))
        return FALSE;

    $classMethod = array_map('strtolower', array_map('trim', explode('.', $classMethod)));

    if (!isset($classMethod[0]) || !$classMethod[0] //type
        || !isset($classMethod[1]) || !$classMethod[1] //class
        || !isset($classMethod[2]) || !$classMethod[2] //method
    )
    return FALSE;

    $type = $classMethod[0];
    $class = $classMethod[1];
    $method = $classMethod[2];

    $key = $type. '.'. $class;

    static $classes = array();

    // if args eq NULL, remove class from $classes
    if (NULL === $args) {
        if (isset($classes[$key]))
            unset($classes[$key]);

        return TRUE;
    }

    if (!isset($classes[$key]) || NULL == $classes[$key]) {
        $classFile = NULL;
        $className = NULL;

        switch($type) {
            // controller
        case 'c':
        case 'controller':
            $className = $class. 'Controller';
            $classFile = APP_ROOT. 'controllers'. DIRECTOR_SEPARATOR. $class. '.class.php';
            break;
            // addons
        case 'a':
        case 'addons':
            $className = $class;
            $classFile = ANTFW_ROOT. 'addons'. DIRECTOR_SEPARATOR. $class. '.class.php';
            if (!file_exists($classFile) || !is_readable($classFile))
                $classFile = APP_ROOT. 'addons'. DIRECTOR_SEPARATOR. $class. '.class.php';
            break;
            // model, default
        case 'm':
        case 'model':
        default:
            $className = $class. 'Model';
            $classFile = APP_ROOT. 'models'. DIRECTOR_SEPARATOR. $class. '.class.php';
            break;
        }

        if (!file_exists($classFile) || !is_readable($classFile))
            return FALSE;

        require $classFile;

        if (!class_exists($className))
            return FALSE;

        $classes[$key] = new $className((array)$constructArgs);
    }

    if (!method_exists($classes[$key], $method))
        return FALSE;

    return $classes[$key]->$method((array)$args);
}


/**
 * runtime log 
 *
 * @param mixed $log
 * @return void
 */
function runtimeLog($log = NULL) {
    if (0 === RUNTIME_LOG)
        return FALSE;

    $except = array('include', 'include_once', 'require', 'require_once');

    $debug = debug_backtrace();
    $isExcept = isset($debug[1]['function']) && in_array($debug[1]['function'], $except)? TRUE: FALSE;

    if (2 !== count($debug) || $isExcept)
        $debug = $debug[0];
    else
        $debug = $debug[1];

    $string = '['. date('y-m-d H:i:s'). ' '. array_sum(explode(' ', microtime())). "] ------------------------------------------------------------\n";
    $string .= <<<EOF
file: {$debug['file']}
line: {$debug['line']}\n
EOF;

    if (!$isExcept) {
        $debug['args'] = print_r($debug['args'], TRUE);
        $string .= <<<EOF
func: {$debug['function']}
args: {$debug['args']}\n
EOF;
    }

    $string .= "msg : ". print_r($log, TRUE). "\n\n";

    switch (RUNTIME_LOG) {
    case 1: // file
        $logDir = APP_ROOT. 'runtime/log';
        if (!is_dir($logDir) && !mkdir($logDir))
            return FALSE;

        $logFile = $logDir. '/'. date('y-m-d'). '.log';

        file_put_contents($logFile, $string, FILE_APPEND);
        break;
    case 2: // database
        break;
    default:
    }

}


/**
 * halt 
 *
 * @param integer $code
 * @param string $msg
 * @param mixed $data 
 *
 * @usage
 *     halt(200, 'This is a test page', $data)
 *     halt(302, '', 'http://http-url/')
 *     halt(406, 'No permission')
 */
function halt($code, $msg = '', $data = NULL) {

    $code = (int)$code;

    if (!$code)
        $code = 200;

    if (301 === $code || 302 === $code) {
        header('location:'. $data);
        exit;
    }

    header('HTTP/1.1 '. $code);

    $data = array('msg'=>$msg, 'data'=>$data);

    'json' === MIME && die(json_encode($data));
    //'xml'  === MIME && die(xml_encode($data)); // todo

    die($msg);
}


/**
 * Cache operation
 *
 * @param string $key
 * @param mixed $value
 * @param integer $expire
 */
function cache($key, $value = DO_GET, $expire = 3600) {
    $key = trim($key);
    if (!$key)
        return FALSE;

    static $redis = NULL;

    // load redis
    if (NULL === $redis) {
        $config = config('db');
        if (NULL === $config || !isset($config['redis']))
            return FALSE;

        $config = $config['redis'];

        if (!isset($config['use']) || !$config['use'] ||
            !isset($config['host']) || !$config['host'])
            return FALSE;

        if (!isset($config['port']))
            $config['port'] = 6379;

        if (!isset($config['expire']))
            $config['expire'] = 3600;

        if (!isset($config['timeout']))
            $config['timeout'] = 2;

        if (!class_exists('Redis'))
            require ANTFW_ROOT. 'addons/redisent.class.php';

        $redis = new Redis();
        if (FALSE === $redis->connect(
            $config['host'],
            $config['port'],
            $config['timeout']
        )) {
            $redis = NULL;
            return FALSE;
        }
    }

    // flush all cache
    if (DO_DELETE === $key)
        return $redis->flushAll();

    // delete cache by special key
    if (DO_DELETE === $value)
        return $redis->delete($key);

    // get cache
    if (DO_GET === $value) {
        $cache = $redis->get($key);
        return NULL === $cache? FALSE: json_decode($cache, TRUE);
    }

    // write cache
    if (isset($args[2]))
        $args[2] = $config['expire'];
    else
        $args[2] = (int)$args[2];

    return $redis->setex($key, $args[2], json_encode($value));
}


/**
 * translate string to local language
 *
 * @param string $key
 * @param mixed $value
 * @return mixed 
 */
function lang($key, $value = DO_GET) {
    static $data = array();

    if (DO_MERGE === $value && is_array($key))
        $data = array_merge($data, $key);

    if (!is_string($key))
        return FALSE;

    $key = trim($key);
    if (!$key)
        return NULL;

    $key = strtoupper($key);

    if (DO_GET === $value) {
        if (isset($data[$key]))
            return $data[$key];
        else
            return $key;
    }

    $data[$key] = $value;
}


/**
 * cookie set/get
 *
 * @param string $key
 * @param mixed $value
 * @param array $options
 * @param boolean $encrypt
 * @return mixed
 */
function cookie($key, $value = DO_GET, $options = array(), $encrypt = FALSE) {
    $key = trim($key);
    if (!$key)
        return NULL;

    $config = array(
        'prefix' => config('cookie_prefix'),
        'expire' => config('cookie_expire'),
        'path' => config('cookie_path'),
        'domain' => config('cookie_path')
    );

    if (!empty($option)) {
        if (is_numeric($option))
            $option = array('expire' => $option);
        elseif (is_string($option))
            parse_str($option, $option);
        $config = array_merge($config, array_change_key_case($option));
    }

    if (is_null($skey)) {
        if (empty($_COOKIE))
            return NULL;
        $prefix = empty($value) ? $config['prefix'] : $value;
        if (!empty($prefix)) {
            foreach ($_COOKIE as $key => $val) {
                if (0 === stripos($key, $prefix)) {
                    setcookie($key, '', time() - 3600, $config['path'], $config['domain']);
                    unset($_COOKIE[$key]);
                }
            }
        }
        return NULL;
    }
    $skey = $config['prefix'] . $skey;
    if (DO_GET === $value) {
        return isset($_COOKIE[$skey]) ? $_COOKIE[$skey] : null; 
    } else {
        if (DO_DELETE === $value) {
            setcookie($skey, '', time() - 3600, $config['path'], $config['domain']);
            unset($_COOKIE[$skey]);
        } else {
            $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
            setcookie($skey, $value, $expire, $config['path'], $config['domain']);
            $_COOKIE[$skey] = $value;
        }
    }
}
